/**
 * @author David Alvarez 789401 & Ulises Juarez 937858
 * @date   22/Sep/06
 */

package com.dekaru.math;

import java.io.*;
import com.dekaru.math.type.*;

public class Matrices {
	
	private static BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
	private static PrintWriter stdOut = new PrintWriter(System.out,true);
	private static PrintWriter stdErr = new PrintWriter(System.out,true);
	
	private static Matrix m1, m2;
	private static boolean val = true;  //Define si el usuario ingreso una opcion correcta o no (para despues preguntar si desea nuevas matrices)
	private static boolean sto = true; //Define si el usuario desea operar sobre las mismas matrices, o introducir nuevas
	
	public static void main(String[] args) throws IOException {

		m1 = new Matrix();
		m2 = new Matrix();

		char opt = ' ';
        while (opt != 'l') {
	        
	        stdOut.println("    a)	cofactor cij de una matriz A");				
	        stdOut.println("    b)	menor ij Mij de un elemento de una matriz A");
	        stdOut.println("    c)	elementos de la diagonal principal y de la diagonal secundaria");
	        stdOut.println("    d)	Suma"); 
	        stdOut.println("    e)	Resta");
	        stdOut.println("    f)	Multiplicacion");
	        stdOut.println("    g)	Transpuesta de una matriz");
	        stdOut.println("    h)	Matriz de Cofactores");
	        stdOut.println("    i)	Adjunta de una matriz");
	        stdOut.println("    j)	Determinante de una matriz");
	        stdOut.println("    k)	Inversa de una matriz");
	        stdOut.println("    l)	Salir");
	        
	        stdOut.print("\n    	>> ");
	        stdOut.flush();
	        opt = stdIn.readLine().charAt(0);
	        stdOut.println();
	        
	        int i, j;
	        
	        switch(opt) {
	        
	        	case('a'): //cofactor de un elemento ij
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
		        	stdOut.print("Renglon del cofactor: ");
					stdOut.flush();
					i = Integer.parseInt(stdIn.readLine());
					stdOut.print("Columna del cofactor: ");
					stdOut.flush();
					j = Integer.parseInt(stdIn.readLine());
	        	
	        		stdOut.println("El cofactor del elemento [" + i + "][" + j + "] es " + m1.cofactor(i,j));
	        		
	        		val = true;
	        		break;
	        			
	        	case('b'): //menor ij
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
		        	stdOut.print("Renglon del menor: ");
					stdOut.flush();
					i = Integer.parseInt(stdIn.readLine());
					stdOut.print("Columna del menor: ");
					stdOut.flush();
					j = Integer.parseInt(stdIn.readLine());
					
					stdOut.println("El menor del elemento [" + i + "][" + j + "] es " + m1.menor(i, j));
	        		
					val = true;
					break;
	        		
	        	case('c'): //elementos de la diagonal principal y de la diagonal secundaria
    				if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		if (m1.getColumnas() == m1.getRenglones()) {
	        			
			        	Double[][] elementos = m1.diagonal();
		        		
			        	stdOut.println("La matriz es: \n" + m1.toString());
			        	
			        	stdOut.println("La diagonal principal es:");
			        	stdOut.print("    >> ");
			        	for (i = 0; i < elementos[0].length; i++) {						//mejorar salida
							stdOut.print(elementos[0][i] + " ");
						}
			        	stdOut.println("\n \nLa diagonal secundaria es:");
			        	stdOut.print("    >> ");
			        	for (i = 0; i < elementos[1].length; i++) {
							stdOut.print(elementos[1][i] + " ");
						}
			        	stdOut.println();
	        		}
	        		else {
	        			
	        			stdErr.println("No se pueden determinar las diagonales debido a que la matriz no es cuadrada.");
	        		}
		        	
		        	val = true;
	        		break;
	        		
	        	case('d'): //suma
	        		if (!sto || m1.isEmpty() || m2.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        			m2 = askMatrix();
	        		}
	        	
	        		if (m1.sameOrder(m2)) {

	        			stdOut.println(m1.getColumnas()+"");
	        			stdOut.println(m1.toString() + "\n + \n" + m2.toString() + "\n = \n" + m1.suma(m2).toString());
	        		}
	        		else {
	        			
	        			stdErr.println("Las matrices que introdujiste no se pueden sumar.");
	        		}
	        		
	        		val = true;
	        		break;
	        		
	        	case('e'): //resta
        			if (!sto || m1.isEmpty() || m2.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        			m2 = askMatrix();
	        		}
	        		
	        		if (m1.sameOrder(m2)) {
	        			
	        			stdOut.println(m1.toString() + "\n - \n" + m2.toString() + "\n = \n" + m1.resta(m2));
				    }	        
					else {
	        			
	        			stdErr.println("Las matrices que introdujiste no se pueden restar.");
	        		}
	        		
	        		val = true;
	        		break;
	        		
	        	case('f'): //multiplicacion
        			if (!sto || m1.isEmpty() || m2.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        			m2 = askMatrix();
	        		}
	        		
	        		if (m1.getRenglones() == m2.getColumnas()) {
	        			
	        			stdOut.println(m1.toString() + "\n * \n" + m2.toString() + "\n = \n" + m1.multiplicacion(m2));
	        		}
    				else {
	        			
	        			stdErr.println("Las matrices que introdujiste no se pueden multiplicar.");
	        		}
	        		
	        		val = true;
	        		break;
	        		
	        	case('g'): //transpuesta
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		stdOut.println("La matriz es: \n" + m1.toString());
		        	stdOut.println("La transpuesta de la matriz es: \n" + m1.transpuesta().toString());
		        	
		        	val = true;
	        		break;
	        		
	        	case('h'): //matriz de cofactores
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		stdOut.println("La matriz es: \n" + m1.toString());
		        	stdOut.println("La matriz de cofactores es: \n" + m1.cofactor().toString());
		        	
		        	val = true;
	        		break;
	        		
	        	case('i'): //adjunta de una matriz
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		stdOut.println("La matriz es: \n" + m1.toString());
		        	stdOut.println("La adjunta de la matriz es: \n" + m1.adjunta().toString());
		        	
		        	val = true;
	        		break;
	        		
	        	case('j'): //determinante
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		stdOut.println("La matriz es: \n" + m1.toString());
	        		stdOut.println("El determinante de la matriz es: \n" + m1.determinante());
		        	
		        	val = true;
	        		break;
	        		
	        	case('k'): //inversa
        			if (!sto || m1.isEmpty()) {
	        			
	        			m1 = askMatrix();
	        		}
	        	
	        		stdOut.println("La matriz es: \n" + m1.toString());
		        	stdOut.println("La inversa de la matriz es: \n" + m1.inversa());
		        	
		        	val = true;
	        		break;
	        	
	        	case('l'): //Termina el programa
	        		stdOut.println("Adiosin!");
	        		System.exit(0);
	        		break;
	        		
        		default:
        			val = false;
        			stdErr.println("Por favor selecciona una opcion valida.");
	        }
	        
	        if (val) {
	        	
	        	stdOut.print("\n Deseas recordar las matrices que introdujiste? (y/n): ");
		        stdOut.flush();
		        char c = stdIn.readLine().charAt(0);
		        if (c == 'y' || c == 'Y') {
		        	
		        	sto = true;
		        }
		        else {
		        	
		        	sto = false;
		        }	        	
	        }
        }
	}

	public static Vector askMatrix() throws IOException {
		
		try {
			
			stdOut.print("No. de renglones: ");
			stdOut.flush();
			int i = Integer.parseInt(stdIn.readLine());
			stdOut.print("No. de columnas: ");
			stdOut.flush();
			int j = Integer.parseInt(stdIn.readLine());
			
			Double matrix[][] = new Double[i][j];

			for (i = 0; i < matrix.length; i++) {
				
				for (j = 0; j < matrix[0].length; j++) {
					
					stdOut.print("["+i+"]["+j+"] :  ");
					stdOut.flush();
					matrix[i][j] = new Double(Double.parseDouble(stdIn.readLine()));
				}
			}
			
			Vector new_matrix = new Vector(matrix);
			return new_matrix;
		}
		catch(NumberFormatException nfe) {
			
			stdErr.println("Por favor revisa el formato de tus numeros.");
		}
		
		return new Vector();
	}
}